﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SSharp.Core.DataTypes;

namespace SSharp.Core.Evaluator {
	/// <summary>
	/// Eval, Apply and Macros should be the core of the metacircular evaluator.
	/// </summary>
	public static partial class Eval {
		private static Evaluator[] evaluators = {
			new SimpleExpressionEvaluator(),
			new VariableEvaluator(),
			new IfEvaluator(),
			new QuoteEvaluator(),
			new QuasiquoteEvaluator(),
			new DefinitionEvaluator(),
			new LambdaEvaluator(),
			new LambdaEvaluator("ƛ"),
			new BeginEvaluator(),
			new ApplicationEvaluator() // ApplicationEvaluator must be the last one
		};

		public static object Evaluate(object expression, IEnvironment env) {
			while (true) {
				EvaluationResult result = EvalExpression(expression, env);
				MoreEvaluationNeeded more = result as MoreEvaluationNeeded;
				if (more != null) {
					expression = more.Result;
					env = more.Environment;
					continue;
				} else {
					return result.Result;
				}
			}
		}

		/// <summary>
		/// Evaluates the given expression in the given environment
		/// </summary>
		internal static EvaluationResult EvalExpression(object expression, IEnvironment env) {
			if (expression == null) {
				throw new ArgumentNullException("expression");
			}

			foreach (Evaluator eval in evaluators) {
				if (eval.CanEvaluate(expression)) {
					return eval.Evaluate(expression, env);
				}
			}

			throw new InvalidOperationException("Unknown expression " + expression);
		}
	}
}